#!python
# -*- coding: utf-8 -*-

import pymysql
import urlparse
import hashlib
import unittest
from .alipay_parameters import *
from .util import generate_trade_no
from .db import get_db
from .admin import login_required
from flask import Blueprint, request, render_template, current_app, url_for
import urllib
import urllib2
from xml.etree import ElementTree as ET
import traceback

alipay = Blueprint("alipay", __name__)

def md5(s):
    m = hashlib.md5()
    m.update(s)
    s1=m.hexdigest()
    return s1

def filter_parameters(d):
    d1 = {}
    for k,v in d.items():
        if v is None:
            continue
        if str(v) == "":
            continue
        if k in ["sign", "sign_type"]:
            continue
        if k not in PAY_INTERFACE_ALLOW_KEYS:
            continue
        d1[k] = v
    return d1

def sign_parameters(params, key, sign_type="MD5"):
    d = []
    for k,v in params.items():
        d.append("%s=%s" % (k,v))
    d.sort()

    s1 = "&".join(d)
    s2="%s%s" % (s1, key)
    s3 = md5(s2)
    return s3

def update_orderinfo(args):
    conn = get_db()
    cur = conn.cursor()
    sql = "select trade_status,refund_status from online_buy where out_trade_no = '%s'" % (args["out_trade_no"],)
    cur.execute(sql)
    rs = cur.fetchall()
    if rs:
        t_s, r_s = rs[0]

        t_s = t_s if t_s else ""
        r_s = r_s if r_s else ""
        args["refund_status"] = args["refund_status"] if args["refund_status"] else ""
        args["trade_status"] = args["trade_status"] if args["trade_status"] else ""

        if r_s == args["refund_status"] and t_s == args["trade_status"]:
            # already processed
            current_app.logger.debug("order %s has been processed, ignore" % args["out_trade_no"])
            cur.close()
            return

        # not processed, do it
        sql = """update online_buy set 
            seller_actions='{seller_actions}', 
            is_total_fee_adjust='{is_total_fee_adjust}', receive_zip='{receive_zip}',
            receive_phone='{receive_phone}', receive_mobile='{receive_mobile}',
            receive_address='{receive_address}', logistics_fee='{logistics_fee}',
            price='{price}', buyer_email='{buyer_email}', discount='{discount}',
            logistics_payment='{logistics_payment}', trade_status='{trade_status}',
            gmt_payment='{gmt_payment}', trade_no='{trade_no}',
            receive_name='{receive_name}', use_coupon='{use_coupon}',
            total_fee='{total_fee}', quantity='{quantity}', gmt_create='{gmt_create}',
            productno='{pid}', refund_status = '{refund_status}'
        where
            out_trade_no = '{out_trade_no}'
        """.format(**args)
    else:
        sql="""insert into online_buy (
            seller_actions,logistics_type,is_total_fee_adjust,receive_zip,
            receive_phone,receive_mobile,out_trade_no,receive_address,logistics_fee,
            price,buyer_email,discount,logistics_payment,trade_status,gmt_payment,
            trade_no,receive_name,use_coupon,total_fee,quantity,gmt_create, productno,
            refund_status
        )
        values (
            '{seller_actions}','{logistics_type}','{is_total_fee_adjust}', '{receive_zip}',
            '{receive_phone}','{receive_mobile}','{out_trade_no}', '{receive_address}',
            '{logistics_fee}','{price}','{buyer_email}','{discount}', '{logistics_payment}',
            '{trade_status}','{gmt_payment}','{trade_no}', '{receive_name}','{use_coupon}',
            '{total_fee}','{quantity}','{gmt_create}', '{pid}', '{refund_status}'
        )
        """.format(**args)
    #current_app.logger.debug("sql %s" % sql)
    cur.execute(sql)
    conn.commit()

    # goods is sent
    if args["trade_status"] == "WAIT_BUYER_CONFIRM_GOODS":
        sql = "update product set instock = instock - 1, selled = selled + 1 where productno = '%s'" % args["pid"]
        cur.execute(sql)
        conn.commit()
    cur.close()

def verify_notify(nid):

    if not current_app.config.get("VERIFY_NOTIFY", False):
        current_app.logger.warn("do not verify the notify from alipay accord the config")
        return True

    partner = current_app.config.get("ALIPAY_SETTINGS").get("partner")
    u = "https://mapi.alipay.com/gateway.do"
    p = {"service":"notify_verify",
            "partner": partner.encode("utf-8") if isinstance(partner, unicode) else partner,
            "notify_id": nid.encode("utf-8") if isinstance(nid, unicode) else nid
            }
    url = "%s?%s" % (u, urllib.urlencode(p))
    f = urllib2.urlopen(url)
    d = f.read()
    f.close()
    current_app.logger.debug("notify_verify return %s" % d)
    if d == "true":
        return True
    current_app.logger.error("verify notify failed, may be this is not alipay notfiy")
    return False


@alipay.route("/alipayapi", methods=["GET", "POST"])
def alipayapi():
    out_trade_no = generate_trade_no()
    args = {"out_trade_no": out_trade_no,
            "service":"create_partner_trade_by_buyer"
            }

    current_app.logger.debug(u"request %s with argument %s" % (url_for(".alipayapi"),
        "&".join(["%s=%s" % (k,v) for k,v in request.values.items()])
        ))
    args.update(current_app.config.get("ALIPAY_SETTINGS",{}))
    pid = request.values.get("productno", "")
    if not pid:
        return "bad request", 400

    args["return_url"] = urlparse.urljoin(
            args["return_url"],
            url_for('.pay_result', pid=pid)
            )
    if args["notify_url"]:
        args["notify_url"] = urlparse.urljoin(
                args["notify_url"],
                url_for('.notify', pid=pid)
            )
    conn = get_db()
    cur = conn.cursor()

    sql = """select productname, productdesc, price, discount
    from product
    where productno = '%s'
    """ % pymysql.escape_string(pid)

    cur.execute(sql)
    rs = cur.fetchall()
    cur.close()
    if not rs:
        return "Not found", 404

    subject, body, price, discount = rs[0]

    args["subject"]=subject
    args["price"] = price
    args["body"] = body

    try:
        quantity = abs(int(request.values.get("quantity", 1)))
    except:
        quantity = 1

    args["quantity"] = quantity
    args["discount"] = "-%.2f" % (abs(float(discount)) * quantity, )
    args["total_fee"] = ""

    args1 = {}
    for k,v in args.items():
        k1 = k
        if isinstance(k, unicode):
            k1 = k.encode("utf-8")
        v1 = v
        if isinstance(v, unicode):
            v1 = v.encode("utf-8")
        args1[k1] = v1

    new_args = filter_parameters(args1)
    if not new_args.has_key("_input_charset"):
        new_args["_input_charset"] = "utf-8"

    sign = sign_parameters(new_args,
            current_app.config.get("ALIPAY_SETTINGS").get("key")
            )
    new_args.update({"sign": sign, "sign_type": "MD5"})

    current_app.logger.debug("call alipay interface with arguments %s" % (
        "&".join(["%s=%s" % (k,v) for k,v in new_args.items()])
        ))

    u = "https://mapi.alipay.com/gateway.do"
    url = "%s?%s" % (u, urllib.urlencode(new_args))
    return u"支付宝跳转中...", 302, {"Location": url}

@alipay.route("/notify", defaults={"pid":"20150001"}, methods = ["GET", "POST"])
@alipay.route("/notify/<pid>", methods = ["GET", "POST"])
def notify(pid):
    args = {}
    for k in ALIPAY_RETURN_PARAMETERS:
        v = request.values.get(k, "")
        if isinstance(v, unicode):
            v = v.encode("utf-8")
        #if str(v) == "":
        #    continue
        args[k] = v

    current_app.logger.debug("notify from alipay with arguments %s" % (
        "&".join(["%s=%s" % (k,v) for k,v in args.items()]),
        ))

    if not verify_notify(args.get("notify_id")):
        return "fail"
    args["pid"] = pid.encode("utf-8")
    update_orderinfo(args) 

    return "success", 200, {"Content-Type": "text/plain"}

@alipay.route("/pay/result/<pid>")
def pay_result(pid):
    args = {}
    for k in ALIPAY_RETURN_PARAMETERS:
        v = request.values.get(k, "")
        if isinstance(v, unicode):
            v = v.encode("utf-8")
        #if str(v) == "":
        #    continue
        args[k] = v

    current_app.logger.debug("return from alipay with arguments %s" % (
        "&".join(["%s=%s" % (k,v) for k,v in args.items()]),
        )
        )
    if  verify_notify(args.get("notify_id")):
        args["pid"] = pid.encode("utf-8")
        if (args["is_success"] == "T"):
            update_orderinfo(args) 
            return render_template("pay_success.html")

    return render_template("pay_fail.html")

@alipay.route("/confirm", methods=["GET", "POST"])
@login_required
def send_goods():
    if request.method == "POST":
        args = dict(
            service="send_goods_confirm_by_platform",
            partner=current_app.config.get("ALIPAY_SETTINGS").get("partner"),
            _input_charset="utf-8",
            trade_no=request.values.get("trade_no"),
            logistics_name=request.values.get("logistics_name"),
            invoice_no=request.values.get("invoice_no"),
            transport_type=request.values.get("transport_type")
        )
        args1={}
        for k,v in args.items():
            v1 = v
            k1 = k
            if isinstance(v, unicode):
                v1 = v.encode("utf-8")
            args1[k1] = v1
        sign=sign_parameters(args1,
                current_app.config.get("ALIPAY_SETTINGS").get("key")
                )
        sign_type="MD5"
        args1["sign"] = sign
        args1["sign_type"]=sign_type
        u = "https://mapi.alipay.com/gateway.do"
        url = "%s?%s" % (u, urllib.urlencode(args1))
        f = urllib2.urlopen(url)
        d = f.read()
        current_app.logger.debug("return from alipay: %s" % d)
        try:
            e = ET.fromstring(d)
        except:
            current_app.logger.ERROR("alipay return invalid xml")
            traceback.print_exc()
            return "FAIL"

        rs = e.findtext("is_success")
        if rs == "F":
            return render_template("send_goods_fail.html", trade_no=args1["trade_no"])
        conn = get_db()
        cur = conn.cursor()
        sql = "select trade_name,invoice_no from trade_info where trade_no = '%s'" % args1["trade_no"]
        cur.execute(sql)
        rs = cur.fetchall()
        if rs:
            l_name,i_no = rs[0]
            if l_name != args1["logistics_name"] and i_no != args1["invoice_no"]:
                sql = """update trade_info 
                set 
                    trade_name = '{logistics_name}'
                    ,invoice_no = '{invoice_no}'
                where 
                    trade_no = '{trade_no}'
                """.format(**args1)
                cur.execute(sql)
                conn.commit()
        else:
            sql = """insert into trade_info (trade_no, trade_name, invoice_no, t_time)
            values('{trade_no}', '{logistics_name}', '{invoice_no}', now())
            """.format(**args1)
            cur.execute(sql)
            conn.commit()
        cur.close()
        send_sms(trade_no = args["trade_no"],
                logistics_name = args["logistics_name"],
                invoice_no = args["invoice_no"]
                )
        return render_template("send_goods_success.html")

    trade_no = request.values.get("trade_no")
    conn = get_db()
    cur = conn.cursor()
    sql = """select
        p.productname,b.receive_name,b.receive_address,
        b.receive_zip,b.receive_phone,b.receive_mobile,
        b.quantity
    from online_buy b 
        join product p on b.productno = p.productno
    where
        b.trade_no = '%s'
    """ % (trade_no,)
    cur.execute(sql)
    rs = cur.fetchall()
    o = rs[0]
    cur.close()
    return render_template("send_goods.html", order = o, trade_no = trade_no)

def send_sms(trade_no, logistics_name, invoice_no):
    conn = get_db()
    cur=conn.cursor()
    sql = """select 
        b.receive_mobile, p.productname 
    from online_buy b 
        join product p on b.productno = p.productno
    where 
        b.trade_no = '%s'
    """ % trade_no
    cur.execute(sql)
    rs = cur.fetchall()
    cur.close()
    phone_no, productname = rs[0]
    if not phone_no:
        return
    if len(phone_no) != 11:
        return

    c = current_app.config.get("SMS_CONFIG")
    
    msg = u"""您购买的爱四季%s已经发货, %s, 单号 %s, 请注意查收快递。【四季宏胜】""" % (productname, logistics_name, invoice_no)
    args = {
            "CorpID":c["uid"],
            "Pwd":c["pwd"],
            "Mobile": phone_no,
            "Content":msg.encode("gbk")
            }
    u = "%s?%s" % (c["url"], urllib.urlencode(args))
    #current_app.logger.debug("url: %s" % u)
    f = urllib2.urlopen(u)
    d = f.read()
    if int(d) != 0:
        current_app.logger.error("send sms return %s" % d)
    return 

if __name__ == "__main__":
    pass
